package com.sl.au.config;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

import javax.servlet.http.HttpSession;
import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.embedded.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import com.sl.au.entity.User;
import com.sl.au.interceptor.HttpSessionConfigurator;
import com.sl.au.interceptor.RequestListener;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import com.sl.au.entity.Module;
import com.sl.au.entity.Option;
import com.sl.au.entity.Account;
import com.sl.au.entity.SocketMessage;
import com.sl.au.service.EventReportService;
import com.sl.au.service.OptionService;
import com.sl.au.service.AccountService;
import com.sl.au.service.EventRegisterService;
import com.sl.au.service.TimeOutTaskService;

@ServerEndpoint(value = "/wcsi-websocket/{aid}/{location}", configurator = HttpSessionConfigurator.class)
@Component
public class AppWebSocketTask {

	private static EventRegisterService eventRegisterService;
	private static EventReportService eventReportService;

	private static OptionService optionService;

	private static AccountService accountService;

	private static TimeOutTaskService timeOutTaskService;
	
	public static TimeOutTaskService getTimeOutTaskService() {
		return timeOutTaskService;
	}

	public OptionService getOptionService() {
		return optionService;
	}

	@Autowired
	public void setOptionService(OptionService optionService) {
		AppWebSocketTask.optionService = optionService;
	}

	@Autowired
	public void setTimeOutTaskService(TimeOutTaskService timeOutTaskService) {
		AppWebSocketTask.timeOutTaskService = timeOutTaskService;
	}

	public static AccountService getAccountService() {
		return accountService;
	}

	@Autowired
	public void setAccountService(AccountService accountService) {
		AppWebSocketTask.accountService = accountService;
	}

	public static EventReportService getEventReportService() {
		return eventReportService;
	}

	@Autowired
	public void setEventReportService(EventReportService eventReportService) {
		AppWebSocketTask.eventReportService = eventReportService;
	}

	public static EventRegisterService getEventRegisterService() {
		return eventRegisterService;
	}

	@Autowired
	public void setEventRegisterService(EventRegisterService eventRegisterService) {
		AppWebSocketTask.eventRegisterService = eventRegisterService;
	}

	// 静态变量，用来记录当前在线连接数。
	private static int onlineCount = 0;

	// concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。
	public static CopyOnWriteArraySet<AppWebSocketTask> webSocketSet = new CopyOnWriteArraySet<AppWebSocketTask>();
	
	public static Set<String> onlineUsers = new HashSet<String>();
	
	public static Set<String> sendUser = new HashSet<String>();
	
	public static Set<String> backUser = new HashSet<String>();

	public static Set<String> noBackUser = new HashSet<String>();

	// 与某个客户端的连接会话，需要通过它来给客户端发送数据
	private Session session;

	// 账户id
	private String aid;

	// socket页面链接位置
	private String location;
	
	private HttpSession httpSession;

	
	public String getAid() {
		return aid;
	}

	public void setAid(String aid) {
		this.aid = aid;
	}

	public String getLocation() {
		return location;
	}

	public void setLocation(String location) {
		this.location = location;
	}

	public Session getSession() {
		return this.session;
	}
	

	public HttpSession getHttpSession() {
		return httpSession;
	}

	public void setHttpSession(HttpSession httpSession) {
		this.httpSession = httpSession;
	}

	public boolean isShow(String aid, String module) {
		Account account = accountService.getRepository().findOne(aid);
		if (account == null) {
			return false;
		}
		for (Module m : account.getRole().getModules()) {
			if (m.getTarget().replace("?device=mobile", "").contains(module)) {
				return true;
			}
		}
		return false;
	}
	
	
//	@Autowired
//	private RequestListener requestListener;
//    @Bean
//    public ServletListenerRegistrationBean<RequestListener> servletListenerRegistrationBean() {
//        ServletListenerRegistrationBean<RequestListener> servletListenerRegistrationBean = new ServletListenerRegistrationBean<>();
//        servletListenerRegistrationBean.setListener(requestListener);
//        return servletListenerRegistrationBean;
//    }

	/**
	 * 连接建立成功调用的方法
	 */
	@OnOpen
	public void onOpen(Session session, @PathParam("aid") String aid, @PathParam("location") String location,EndpointConfig config) {
		
		HttpSession httpSession= (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
		Account a = (Account) httpSession.getAttribute("account");
		if(a == null) {
			return;
		}
		
		this.session = session;
		this.aid = aid;
		this.location = location;
		this.httpSession = httpSession;
		webSocketSet.add(this); // 加入set中
		if (location.equals("header")) {
			if(!onlineUsers.contains(aid)) {
				onlineUsers.add(aid);
				addOnlineCount(); // 在线数加1
			}
			System.out.println("有新连接加入！当前在线人数为" + getOnlineCount());
		}
		Account account = accountService.getRepository().findOne(aid);
		String roleId = account.getRole().getId();
		// 群发消息
		SocketMessage message = new SocketMessage();
		message.setOnlinePerson(Integer.toString(getOnlineCount()));
		
		for (AppWebSocketTask item : webSocketSet) {
			try {
				// 通知header和footer的消息
				if (item.getLocation().equals("header")) {
					if (item.getAid().equals(aid)) {
						if (isShow(aid, "underTimeout")) {// 即将超时的内部事件信息
							Option type = optionService.getRepository().findByGroupAndTitle("内部事件流转状态", "处理中").get(0);
//							message.setUnderTimeout(eventRegisterService.findCountUnderTimeoutEvent(type) + "");
							message.setUnderTimeout(eventRegisterService.findCountUnderTimeoutEventByRole(roleId,type) + "");
						}
						if (isShow(aid, "eventRegister")) {
//							message.setWaitingAccept(Integer.toString(eventReportService.getWaitingAcceptEventCountByAccount(aid)));
							message.setWaitingAccept(Integer.toString(eventReportService.getWaitingAcceptEventCountByAccountByRole(roleId, aid)));
						} else {
							message.setWaitingAccept(null);
							message.setRejectConfirm(null);
							message.setWaitingPublic(null);
						}
						if (isShow(aid, "timeOutDeal")) {
//							message.setDealEventOverTime(Integer.toString(timeOutTaskService.getTimeOutDealCount("1")));
							message.setDealEventOverTime(Integer.toString(timeOutTaskService.getTimeOutDealCountByRole(roleId, "1")));
						} else {
							message.setDealEventOverTime(null);
						}
						if (isShow(aid, "timeOutReceive")) {
//							message.setReceiveEventOverTime(Integer.toString(timeOutTaskService.getTimeOutReceiveCount("1")));
							message.setReceiveEventOverTime(Integer.toString(timeOutTaskService.getTimeOutReceiveCountByRole(roleId, "1")));
						} else {
							message.setReceiveEventOverTime(null);
						}
					} else {
						message.setWaitingAccept(null);
						message.setDealEventOverTime(null);
						message.setReceiveEventOverTime(null);
						message.setRejectConfirm(null);
						message.setWaitingPublic(null);
					}
					item.sendMessage(JSONObject.fromObject(message).toString());// JSONArray.fromObject(message).toString());
				} else if (location.equals("eventReport")) {
					// 暂不做任何处理
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		/*
		 * Point point =new Point(); point.setX(100); point.setY(200); JSONArray
		 * test = JSONArray.fromObject(point); try {
		 * sendMessage(test.toString());
		 * sendMessage("在线人数:"+getOnlineCount()+"人"); } catch (IOException e) {
		 * System.out.println("IO异常"); }
		 */
	}

	/**
	 * 连接关闭调用的方法
	 */
	@OnClose
	public void onClose() {
		String tempLocation = this.location;
		webSocketSet.remove(this); // 从set中删除
		if (tempLocation.equals("header")) {
			if(onlineUsers.contains(this.aid)) {
				onlineUsers.remove(this.aid);
				subOnlineCount(); // 在线数减1
			}
			System.out.println("有一连接关闭！当前在线人数为" + getOnlineCount());

			// 群发消息
			SocketMessage message = new SocketMessage();
			message.setOnlinePerson(Integer.toString(getOnlineCount()));
			for (AppWebSocketTask item : webSocketSet) {
				try {
					if (item.getLocation().equals("header")) {
						item.sendMessage(JSONObject.fromObject(message).toString());// JSONArray.fromObject(message).toString());
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 收到客户端消息后调用的方法
	 *
	 * @param message
	 *            客户端发送过来的消息
	 */
	@OnMessage
	public void onMessage(String message, Session session) {
//		System.out.println("来自客户端的消息:" + message);
		if(message.equals("heart")) {
			if(!backUser.contains(this.aid)) {
				backUser.add(this.aid);
			}
		}
	}

	/**
	 * 
	 * @param session
	 * @param error
	 */
	@OnError
	public void onError(Session session, Throwable error) {
		System.out.println("发生错误");
//		if(this.location.equals("header")) {
//			if(onlineUsers.contains(this.aid)) {
//				this.httpSession.setAttribute("account", null); 
//				onlineUsers.remove(this.aid);
//				subOnlineCount();
//			}
//		}
//		webSocketSet.remove(this);
//		error.printStackTrace();
	}

	public void sendMessage(String message) throws IOException {
		this.session.getBasicRemote().sendText(message);
		// this.session.getAsyncRemote().sendText(message);
	}

	/**
	 * 群发自定义消息
	 */
	public static void sendInfo(String message) throws IOException {
		for (AppWebSocketTask item : webSocketSet) {
			try {
				item.sendMessage(message);
			} catch (IOException e) {
				continue;
			}
		}
	}

	public static synchronized int getOnlineCount() {
		return onlineCount;
	}

	public static synchronized void addOnlineCount() {
		AppWebSocketTask.onlineCount++;
	}

	public static synchronized void subOnlineCount() {
		AppWebSocketTask.onlineCount--;
	}

	public static synchronized void subOnlineCount(int count) {
		AppWebSocketTask.onlineCount -= count;
	}
	
	public static synchronized void reSetOnlineCount() {
		AppWebSocketTask.onlineCount = AppWebSocketTask.onlineUsers.size();
	}
	
	public static void doWork() throws IOException {

		noBackUser.removeAll(backUser);
		onlineUsers.removeAll(noBackUser);
		reSetOnlineCount();
		noBackUser.clear();
		backUser.clear();
		noBackUser.addAll(onlineUsers);
		for (AppWebSocketTask item : webSocketSet) {
			if(item.location.equals("header")) {
				if(onlineUsers.contains(item.aid)) {
					item.sendMessage("heart");
				}else {
					item.httpSession.setAttribute("account", null);
					webSocketSet.remove(item);
				}
			}
		}
	}

}
